home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / Tools / shar-3.49 / shar.c < prev    next >
C/C++ Source or Header  |  1995-05-03  |  38KB  |  1,391 lines

  1. char *revision = "3.49";
  2. char RCS_ID[] = "$Header: /u/rhg/src/shar/shar.c,v 3.49 90/09/12 15:14:41 rhg Exp $";
  3. /*
  4. ** shar.c
  5.  
  6.   Defined functions:
  7.     gen_mkdir(path)
  8.     gen_mkdir_script(path)
  9.     setTOUCH()
  10.     walktree(rtn,rootname)
  11.     header(argc,argv)
  12.     helpuser()
  13.     main(argc,argv)
  14.     mode_map(mode,mode_str)
  15.     shar(file,RstrName)
  16.  
  17. */
  18. /*+:EDITS:*/
  19. /*:09-12-1990-14:24-rhg@cps.com-added missing return(0) to walkdown */
  20. /*:09-12-1990-14:13-rhg@cps.com-deleted some redundant, unused, code */
  21. /*:09-12-1990-00:28-rhg@cps.com-added more directions to the shar header */
  22. /*:09-09-1990-20:12-rhg@cps.com-added CLOSEDIR_VOID */
  23. /*:09-09-1990-18:42-rhg@cps.com-added check for "From" under OptPREFIX */
  24. /*:09-09-1990-11:55-rhg@cps.com-modified code under NOT STR(N)CMP_IS_FAST */
  25. /*:09-08-1990-21:20-rhg@cps.com-added NO_DIRENT for SunOS 3 sys/dir.h */
  26. /*:09-08-1990-21:04-rhg@cps.com-fixed bug in PREFIX check: strcmp(line,Delim) */
  27. /*:08-06-1990-00:40-rhg@cps.com-revised Cut message to be more explanatory */
  28. /*:08-05-1990-14:04-rhg@cps.com-merged Rname into walktree */
  29. /*:08-05-1990-12:11-rhg@cps.com-added walktree & support for sharing dirs */
  30. /*:08-05-1990-09:05-rhg@cps.com-change -Bn, -t, and -b to -bn, -T, and -B */
  31. /*:08-04-1990-15:31-rhg@cps.com-added -Bn to set compress -bn (default 12) */
  32. /*:08-04-1990-15:31-rhg@cps.com-changed shar3_???_.tmp to _shar_???_.tmp */
  33. /*:08-04-1990-15:22-rhg@cps.com-added check for "exit 0" under OptPREFIX */
  34. /*:08-04-1990-14:32-rhg@cps.com-added -m to generate TOUCH (default off) */
  35. /*:08-04-1990-14:18-rhg@cps.com-reversed the meaning of -x and deleted -O */
  36. /*:06-14-1990-14:48-rhg@cps.com-made Split and eXists compatible.
  37. /*:06-14-1990-14:18-rhg@cps.com-made -x the default and added -O
  38. /*:06-14-1990-12:44-rhg@cps.com-always terminate the && and report failures
  39. /*:06-14-1990-12:28-rhg@cps.com-clear mkdir_already between -l files
  40. /*:06-14-1990-12:14-rhg@cps.com-change PREFIX from a #define to an int variable.
  41. /*:04-19-1990-22:49-rhg@cps.com-get rid of "set" so "sh sharfil -c" will work */
  42. /*:04-19-1990-21:52-rhg@cps.com-add -F to clear OptPREFIX */
  43. /*:04-18-1990-08:49-rhg@cps.com-add OptPREFIX (for now, always on) */
  44. /*:07-09-1990-19:24-wht@n4hgf-back to fgrep amc -- fits more -m touches */
  45. /*:07-01-1990-18:37-wht@n4hgf-wait() needed after fork() */
  46. /*:05-19-1990-02:47-wht@n4hgf-change fgrep amc to mmdd */
  47. /*:05-16-1990-01:53-wht@n4hgf-Archive-name had extra period sometimes */
  48. /*:05-10-1990-20:39-wht@n4hgf-altos does not not like at-sign in filenames */
  49. /*:05-10-1990-13:38-wht@n4hgf-add -V Vanilla mode */
  50. /*:05-07-1990-00:06-wht@n4hgf-test all mallocs for Purity Of Essence */
  51. /*:05-07-1990-00:06-wht@n4hgf-add -S switch */
  52. /*:05-05-1990-01:37-relay.EU.net!rivm!a3-dont assume vax is running BSD */
  53. /*:04-18-1990-02:01-wht@n4hgf-3.20 rhg@cps.com did all the NICE work */
  54. /*:04-17-1990-14:30-rhg@cps.com-pretty up if-then-else-fi in shar file */
  55. /*:04-17-1990-12:13-rhg@cps.com-add Split and renamed old -l to -L */
  56. /*:04-17-1990-12:13-rhg@cps.com-add -c option to shar file execution */
  57. /*:04-17-1990-11:20-rhg@cps.com-simplify TOUCH logic in shar file */
  58. /*:04-17-1990-10:27-rhg@cps.com-create setTOUCH to avoid duplicate code */
  59. /*:04-17-1990-04:43-rhg@cps.com-add missing && to commands in shar file(s) */
  60. /*:04-17-1990-02:03-rhg@cps.com-add Compress */
  61. /*:04-16-1990-17:08-rhg@cps.com-add AvoidPipes as well as code to use pipes */
  62. /*:04-03-1990-20:09-wht@n4hgf-3.11 */
  63. /*:04-01-1990-13:20-pat@rwing-correct case on M option in getopt() call */
  64. /*:04-01-1990-13:50-pat@rwing-change defaults on -v, -w to be on */
  65. /*:03-29-1990-18:23-wht@n4hgf-add automatic sequent support */
  66. /*:03-28-1990-15:56-wht@n4hgf-add mode and length net.bandwidth chrome */
  67. /*:03-28-1990-14:23-wht@n4hgf-correct some runtime diagnostics */
  68. /*:11-14-1989-02:21-wht-SHAR_EOF was botched if last file char not newline */
  69. /*:11-02-1989-14:11-wht-add touch -am */
  70.  
  71. /*
  72.  Shar puts readable text files together in a package
  73.  from which they are easy to extract.
  74.  earlier attribution wht@n4hgf has:    decvax!microsof!uw-beave!jim
  75.                                     (James Gosling at CMU)
  76. */
  77. /*
  78.  *    I have made several mods to this program:
  79.  *
  80.  *    1) the -----Cut Here-----... now preceds the script.
  81.  *    2) the cat has been changed to a sed which removes a prefix
  82.  *    character from the beginning of each line of the extracted
  83.  *    file, this prefix character is added to each line of the archived
  84.  *    files and is not the same as the first character of the
  85.  *    file delimeter.
  86.  *    3) added several options:
  87.  *        -c    - add the -----Cut Here-----... line.
  88.  *        -d'del' - change the file delimeter to del.
  89.  *        -s    - cause the resulting script to print the wc of
  90.  *              the orignal file and the wc of the extracted
  91.  *              file.
  92.  *
  93.  *                Michael A. Thompson
  94.  *                Dalhousie University
  95.  *                Halifax, N.S., Canada.
  96.  */
  97.  
  98. /*
  99.  *    I, too, have been hacking this code. This is the version on sixhub
  100.  *        bill davidsen (davidsen@sixhub.uucp)
  101.  *
  102.  *    - added support for binary files
  103.  *    - automatic creation of limited size multiple file archives,
  104.  *      each of which may be unpacked separately, and with sequence
  105.  *      checking.
  106.  *    - support for mixed text and binary files
  107.  *    - preserve file permissions
  108.  *    - restore to filename rather than pathname
  109.  *
  110.  */
  111. /*
  112.  *  One good hack deserves another ... this version generates shell
  113.  *  code which attempts to create missing directories
  114.  *  handle deviants sun, vax, pyr (pyramid), SCO XENIX/UNIX automatically
  115.  *  for sequent, add -DBSD42
  116.  *  force Verbose on
  117.  *  if unsharing system's touch Sys V compatible (allows touch -m),
  118.  *  restore file dates
  119.  *  -n switch puts an alpha "name" in header
  120.  *  -a (if also -n) puts "Submitted-by:" & "Archive-name: <name>/part##
  121.  *  use getopt
  122.  *  as well as some other chrome-plated junque
  123.  *  ...!gatech!emory!tridom!wht (wht%n4hgf@gatech.edu) Warren Tucker
  124.  *
  125.  *  3.11 - Fri Apr  6 14:21:51 EDT 1990
  126.  *  With due deference to davidsen@sixhub, more changes..... copies
  127.  *  of this, like 3.10,  were mailed to him:
  128.  *  From wht  Fri Apr  6 15:14:30 1990 remote from n4hgf
  129.  *  Received: by n4hgf.UUCP (smail2.5-UNIX/386 5.3.2)
  130.  *      id AA01781; 6 Apr 90 15:14:30 EDT (Fri)
  131.  *  Date: Fri, 6 Apr 90 15:14:30 EDT
  132.  *  X-Mailer: Mail User's Shell (6.5 4/17/89)
  133.  *  From: wht@n4hgf (Warren Tucker)
  134.  *  To: davidsen@sixhub
  135.  *  Subject: shar 3.11
  136.  *  X-Bang-Reply-to: gatech!n4hgf!wht -or- emory!tridom!n4hgf!wht
  137.  *  Reply-to: wht%n4hgf@gatech.edu
  138.  *  Message-Id: <9004061514.AA01781@n4hgf.UUCP>
  139.  *
  140.  *  1. changes suggested by pat@rwing (Pat Myrto) and silvert@cs.dal.ca
  141.  *  (Bill Silvert)
  142.  *  2. fixes to who_am_i code in who@where.c
  143.  *
  144.  *  3.20 - Wed Apr 18 01:58:32 EDT 1990
  145.  *  changes were made per edit notes by
  146. From: gatech!mailrus!uunet!cpsolv.CPS.COM!rhg (Richard H. Gumpertz)
  147.  *  ...!gatech!n4hgf!wht (wht%n4hgf@gatech.edu) Warren Tucker
  148.  *
  149.  */
  150.  
  151. #include <stdio.h>
  152. #include <sys/types.h>
  153. #include <time.h>
  154. #include <sys/stat.h>
  155. #include <ctype.h>
  156.  
  157. /* assume system v unless otherwise fixed */
  158. #if (defined(pyr) || defined(vax) || defined(sequent)) && !defined(BSD42) && !defined(SYS5)
  159. #define BSD42
  160. #endif
  161. #if defined(sun)    /* this miscreant doesn't exactly fit BSD or SYSV */
  162. #undef BSD42
  163. #undef SYS5
  164. #endif
  165. #if !defined(BSD42) && !defined(sun) && !defined(SYS5)
  166. #define SYS5
  167. #endif
  168.  
  169. #if defined(sun) || defined(BSD42)
  170. #define strchr    index
  171. #define strrchr    rindex
  172. #endif
  173.  
  174. char *strchr();
  175. char *strrchr();
  176. #ifdef __STDC__ /* my concession to ANSI-pansiness */
  177. void *malloc();
  178. #else
  179. char *malloc();
  180. #endif
  181. FILE *fdopen();
  182. FILE *popen();
  183.  
  184. #define    DELIM        "SHAR_EOF"/* put after each file */
  185. #define PREFIX1        'X'    /* goes in front of each line */
  186. #define PREFIX2        'Y'    /* goes in front of each line if Delim[0] == PREFIX1 */
  187. #define WC            "wc -c <"
  188.  
  189. int PREFIX = PREFIX1;    /* Character to get at the beginning of each line */
  190.  
  191. int Archive_name = 0;    /* option to generate "Archive-name:" headers */
  192. int Verbose = 1;        /* option to provide append/extract feedback */
  193. int Wc_c = 1;            /* option to provide wc checking */
  194. char *Delim = DELIM;    /* pointer to delimiter string */
  195. int OptPREFIX = 1;        /* suppress PREFIX unless 1st char forces it */
  196. int Cut = 0;            /* option to provide cut mark */
  197. char *CutMessage = "---- Cut Here and feed the following to sh ----\n";
  198. int Binary = 0;            /* flag for binary files */
  199. int AvoidPipes = 0;        /* use temp file instead of pipe to feed uudecode, etc.
  200.                            (better error detection at expense of disk space) */
  201. int Vanilla = 0;        /* no Brown-Shirt mode */
  202. int Touch = 0;            /* generate $TOUCH commands */
  203. int Compress = 0;        /* run input files through compress (requires Binary) */
  204. int CompressBits = 12;    /* -b option to compress */
  205. int Mixed = 0;            /* mixed text and binary files */
  206. int eXists = 1;            /* check if file exists */
  207. int InterOW = 0;        /* interactive overwrite */
  208. int PosParam = 0;        /* allow positional parameters */
  209. int FileStrip;            /* strip directories from filenames */
  210. #ifdef    DEBUG
  211. int de_bug = 0;            /* switch for debugging on */
  212. #define DeBug(f,v) if (de_bug) printf(f, v)
  213. #else    /* normal compile */
  214. #define DeBug(f,v)        /* do nothing */
  215. #endif
  216.  
  217. FILE *fpout = stdout;
  218. int shar();
  219. unsigned limit = 0;
  220. int Split = 0;            /* Split files in the middle */
  221. long ftell();
  222. long TypePos;            /* position for archive type message */
  223. long EndHeadPos;        /* position for first file in the shar file */
  224. char outname[50];        /* base for output filename */
  225. char filename[50];        /* actual output filename */
  226. char *sharname = (char *)0;
  227. char *submitter = (char *)0;
  228. int filenum = 0;        /* output file # */
  229. struct stat fst;        /* check file type, access */
  230.  
  231. main(argc,argv)
  232. char **argv;
  233. {
  234. int status = 0;
  235. int stdin_file_list = 0;
  236. char *oname;
  237. int c;
  238. extern int optind;
  239. extern char *optarg;
  240.  
  241.     while((c = getopt(argc,argv,"VmSvwd:BTCb:xXcfMpPFas:n:l:L:o:h")) != -1)
  242.     {
  243.         switch(c)
  244.         {
  245.         case 'V':
  246.             Vanilla = 1;
  247.             break;
  248.         case 'm':
  249.             Touch = 1;
  250.             break;
  251.         case 'S':
  252.             stdin_file_list = 1;
  253.             break;
  254.         case 'v':
  255.             Verbose = 0;
  256.             break;
  257.         case 'w':
  258.             Wc_c = 0;
  259.             break;
  260.         case 'd':
  261.             Delim = optarg;
  262.             PREFIX = (Delim[0] == PREFIX1 ? PREFIX2 : PREFIX1);
  263.             break;
  264.         case 'B': /* binary files */
  265.             Binary = 1;
  266.             Compress = 0;
  267.             break;
  268.         case 'T': /* text mode */
  269.             Binary = 0;
  270.             Compress = 0;
  271.             break;
  272.         case 'b': /* Compress bits */
  273.             CompressBits = atoi(optarg);
  274.             /* fall through to -C */
  275.         case 'C': /* Compress */
  276.             Binary = 1;
  277.             Compress = 1;
  278.             break;
  279.         case 'x': /* don't worry whether the file exist */
  280.             eXists = 0;
  281.             break;
  282.         case 'X': /* ask the user whether to overwrite existing files */
  283.             InterOW = 1;
  284.             eXists = 1;
  285.             break;
  286.         case 'c':
  287.             Cut = 1;
  288.             break;
  289.         case 'f': /* filenames only */
  290.             FileStrip = 1;
  291.             break;
  292.         case 'M': /* mixed text and binary */
  293.             Mixed = 1;
  294.             break;
  295.         case 'p': /* allow positional parameters */
  296.             PosParam = 1;
  297.             break;
  298.         case 'P': /* use temp files instead of pipes in the shar file */
  299.             AvoidPipes = 1;
  300.             break;
  301.         case 'F': /* force PREFIX to be put out even if not required */
  302.             OptPREFIX = 0;
  303.             break;
  304.         case 'l': /* soft size limit in k */
  305.             if((limit = atoi(optarg)) > 1)
  306.                 --limit;
  307.             Split = 0;
  308.             DeBug("Soft limit %dk\n",limit);
  309.             break;
  310.         case 'L': /* hard size limit in k */
  311.             if((limit = atoi(optarg)) > 1)
  312.                 --limit;
  313.             Split = (limit != 0);
  314.             AvoidPipes = 1;
  315.             DeBug("Hard limit %dk\n",limit);
  316.             break;
  317.         case 'n': /* name of archive */
  318.             sharname = optarg;
  319.             break;
  320.         case 's': /* submitter */
  321.             submitter = optarg;
  322.             break;
  323.         case 'a': /* generate Archive-name: headers */
  324.             Archive_name = 1;
  325.             break;
  326.         case 'o': /* specify output file */
  327.             oname = optarg;
  328.             strcpy(outname,oname);
  329.             strcat(outname,".");
  330.             filenum = 1;
  331.             strcpy(filename,outname);
  332.             strcat(filename,"01");
  333.             fpout = fopen(filename,"w");
  334.             if(!fpout)
  335.             { /* creation error */
  336.                 perror("can't create output file");
  337.                 exit(1);
  338.             }
  339.             break;
  340. #ifdef    DEBUG
  341.         case '$': /* totally undocumented $ option, debug on */
  342.             de_bug = 1;
  343.             break;
  344. #endif
  345.         default: /* invalid option */
  346.         case 'h': /* help */
  347.             helpuser();
  348.             break;
  349.         }
  350.     }
  351.  
  352.     if(Vanilla)
  353.     {
  354.         fprintf(stderr,"Vanilla mode disabling years of progress :-)\n");
  355.         Wc_c = 0;
  356.         OptPREFIX = 0;
  357. #ifdef V_AVOIDPIPES    /* pipes are benign and only used with uudecode anyway */
  358.         AvoidPipes = 1;
  359. #endif /* V_AVOIDPIPES */
  360. #ifdef V_NOFORCE    /* If the user specifies non-defaults, let him have them */
  361. #else
  362.         Touch = 0;
  363.         InterOW = 0;
  364.         if(Binary || Mixed || Compress || PosParam)
  365.             fprintf(stderr,"WARNING: non-Text storage options overridden.\n");
  366.         Binary = 0;
  367.         Mixed = 0;
  368.         Compress = 0;
  369.         PosParam = 0;
  370. #endif /* V_NOFORCE */
  371.     }
  372.  
  373.     if(stdin_file_list)
  374.     {
  375.         char stdin_buf[258];
  376.         argc = 0;
  377.         if(!(argv = (char **)malloc(1024 * sizeof(char *))))
  378.             goto MEMORY_ERROR;
  379.         stdin_buf[0] = 0;
  380.         while(fgets(stdin_buf,sizeof(stdin_buf),stdin))
  381.         {
  382.             if(argc == 1024)
  383.             {
  384.                 fprintf(stderr,"max files from stdin is 1024!\n");
  385.                 exit(1);
  386.             }
  387.             if(stdin_buf[0])
  388.                 stdin_buf[strlen(stdin_buf) - 1] = 0;
  389.             if(!(argv[argc] = malloc(strlen(stdin_buf) + 1)))
  390.             {
  391. MEMORY_ERROR: /* NOT likely, but free software must pure as snow! */
  392.                 fprintf(stderr,"out of memory handling stdin input at %d\n",
  393.                     argc);
  394.                 exit(1);
  395.             }
  396.             strcpy(argv[argc],stdin_buf);
  397.             ++argc;
  398.             stdin_buf[0] = 0;
  399.         }
  400.         optind = 0;
  401.     }
  402.  
  403.     if(optind >= argc)
  404.     {
  405.         fprintf(stderr,"shar: No input files\n");
  406.         helpuser();
  407.         exit(1);
  408.     }
  409.  
  410.     if(Archive_name && !sharname)
  411.     {
  412.         fprintf(stderr,"shar: -n must accompany -a\n");
  413.         helpuser();
  414.         exit(1);
  415.     }
  416.  
  417.     if(!submitter)
  418.     {
  419.         if(!(submitter = malloc(128)))
  420.         {
  421.             fprintf(stderr,"memory allocation failed\n"); /* NOT likely */
  422.             exit(1);
  423.         }
  424.         who_where(submitter);
  425.     }
  426.  
  427.     if(header(argc-optind,&argv[optind]))
  428.         exit(2);
  429.  
  430.     if(InterOW)
  431.     {
  432.         Verbose = 1;
  433.         fputs("wish=\n",fpout);
  434.         if(Archive_name)
  435.         {
  436.             fprintf(stderr,
  437.                 "PLEASE do not submit -X shars to the usenet or other\n");
  438.             fprintf(stderr,
  439.                 "public networks.  They will cause problems.\n");
  440.         }
  441.     }
  442.  
  443.     EndHeadPos = ftell(fpout);
  444.  
  445.     for( ; optind < argc; ++optind)
  446.     { /* process positional parameters and files */
  447.         if(PosParam)
  448.         {        /* allow -B and -T and -C inline */
  449.             if(strcmp(argv[optind],"-B") == 0)
  450.             { /* set binary */
  451.                 Binary = 1;
  452.                 Compress = 0;
  453.                 continue;
  454.             }
  455.             if(strcmp(argv[optind],"-T") == 0)
  456.             { /* set mode text */
  457.                 Binary = 0;
  458.                 Compress = 0;
  459.                 continue;
  460.             }
  461.             if(strcmp(argv[optind],"-C") == 0)
  462.             { /* set compress */
  463.                 Binary = 1;
  464.                 Compress = 1;
  465.                 continue;
  466.             }
  467.         }
  468.         status += walktree(shar,argv[optind]);
  469.     }
  470.  
  471.     /* delete the sequence file, if any */
  472.     if(Split && filenum > 1)
  473.     {
  474.         fputs("rm -f _shar_seq_.tmp\n",fpout);
  475.         fputs("echo You have unpacked the last part\n",fpout);
  476.         if(!Verbose)
  477.             fprintf(stderr,"Created %d files\n",filenum);
  478.     }
  479.     fputs("exit 0\n",fpout);
  480.     exit(status);
  481. }
  482.  
  483. /*+-----------------------------------------------------------------------
  484.     mode_map(mode,mode_str)    build drwxrwxrwx string
  485. ------------------------------------------------------------------------*/
  486. char *
  487. mode_map(mode,mode_str)
  488. unsigned short mode;
  489. char *mode_str;
  490. {
  491. #ifdef THIS_IS_NOT_NEEDED_FOR_SHAR
  492. register unsigned ftype = mode & S_IFMT;
  493. #endif
  494. register char *rtn;
  495. static char result[12];
  496.  
  497.     rtn = (mode_str == (char *)0) ? result : mode_str;
  498.  
  499.     /*          drwxrwxrwx */
  500.     /*          0123456789 */
  501.     strcpy(rtn,"----------");
  502.  
  503. #ifdef THIS_IS_NOT_NEEDED_FOR_SHAR
  504.     switch(ftype)
  505.     {
  506.         case S_IFIFO:    *rtn = 'p'; break; /* FIFO (named pipe) */
  507.         case S_IFDIR:    *rtn = 'd'; break; /* directory */
  508.         case S_IFCHR:    *rtn = 'c'; break; /* character special */
  509.         case S_IFBLK:    *rtn = 'b'; break; /* block special */
  510.         case S_IFREG:    *rtn = '-'; break; /* regular */
  511.  
  512. #if defined(sun) | defined(BSD42)
  513.         case S_IFLNK:    *rtn = 'l'; break; /* symbolic link */
  514.         case S_IFSOCK:    *rtn = 's'; break; /* socket */
  515. #endif
  516.  
  517. #if defined (SYS5)
  518.         case S_IFNAM:                        /* name space entry */
  519.             if(mode & S_INSEM)                /* semaphore */
  520.             {
  521.                 *rtn = 's';
  522.                 break;
  523.             }
  524.             if(mode & S_INSHD)                /* shared memory */
  525.             {
  526.                 *rtn = 'm';
  527.                 break;
  528.             }
  529. #endif
  530.  
  531.         default:        *rtn = '?'; break;    /* ??? */
  532.     }
  533. #endif /* THIS_IS_NOT_NEEDED_FOR_SHAR */
  534.  
  535.     if(mode & 000400) *(rtn + 1) = 'r';
  536.     if(mode & 000200) *(rtn + 2) = 'w';
  537.     if(mode & 000100) *(rtn + 3) = 'x';
  538.     if(mode & 004000) *(rtn + 3) = 's';
  539.     if(mode & 000040) *(rtn + 4) = 'r';
  540.     if(mode & 000020) *(rtn + 5) = 'w';
  541.     if(mode & 000010) *(rtn + 6) = 'x';
  542.     if(mode & 002000) *(rtn + 6) = 's';
  543.     if(mode & 000004) *(rtn + 7) = 'r';
  544.     if(mode & 000002) *(rtn + 8) = 'w';
  545.     if(mode & 000001) *(rtn + 9) = 'x';
  546.     if(mode & 001000) *(rtn + 9) = 't';
  547.  
  548.     return(rtn);
  549.  
  550. }    /* end of mode_map */
  551.  
  552. void
  553. setTOUCH()
  554. {
  555.     if(Touch)
  556.     {
  557.         fputs("if touch 2>&1 | fgrep 'amc' > /dev/null\n",fpout);
  558.         fputs(" then TOUCH=touch\n",fpout);
  559.         fputs(" else TOUCH=true\n",fpout);
  560.         fputs("fi\n",fpout);
  561.     }
  562. } /* end of setTOUCH */
  563.  
  564. #ifdef NO_WALKTREE
  565.  
  566. int
  567. walktree(rtn,file)                /* dummy walktree */
  568. int (*rtn)(/*file,rname*/);    /* may also assume fst is set */
  569. char *file;
  570. {
  571.     register char *rname;
  572.  
  573.     if(stat(file,&fst))
  574.     {
  575.         fprintf(stderr,"shar: Can't access %s\n",file);
  576.         return(1);
  577.     }
  578.  
  579.     if(FileStrip)
  580.     { /* use just the filename */
  581.         rname = file + strlen(file);
  582.         while(rname > file && *rname != '/')
  583.             --rname;
  584.         if(*rname == '/')
  585.             ++rname;
  586.     }
  587.     else
  588.         rname = file;
  589.     if(!strncmp(rname,"./",2) && rname[2])
  590.         rname += 2;
  591.  
  592.     return((*rtn)(file,rname));
  593. }
  594.  
  595. #else /* NO_WALKTREE*/
  596.  
  597. #ifdef NO_DIRENT
  598.  
  599. #include <sys/dir.h>            /* SunOS 3, etc. */
  600. #define DIRENTRY struct direct
  601.  
  602. #else /* NO_DIRENT */
  603.  
  604. #include <dirent.h>            /* Doug Gwyn's dirent routines */
  605. #define DIRENTRY struct dirent
  606.  
  607. #endif /* NO_DIRENT */
  608.  
  609. DIR *opendir();
  610. DIRENTRY *readdir();
  611.  
  612. int
  613. walkdown(rtn,file,filelen,rname)
  614. int (*rtn)(/*file,rname*/);    /* may also assume fst is set */
  615. char *file, *rname;            /* *rname must be *file + n where n < filelen */
  616. int filelen;
  617. {
  618.     DIR *dirp;
  619.     DIRENTRY *dp;
  620.  
  621.     if(stat(file,&fst))
  622.     {
  623.         fprintf(stderr,"shar: Can't access %s\n",file);
  624.         return(1);
  625.     }
  626.  
  627.     if((fst.st_mode & S_IFMT) != S_IFDIR)
  628.         return((*rtn)(file,rname));
  629.  
  630.     if(!(dirp = opendir(file)))
  631.     {
  632.         fprintf(stderr,"shar: unable to open directory %s",file);
  633.         return(1);
  634.     }
  635.  
  636.     if(!strcmp(rname,"."))
  637.         rname += 2;                /* avoid "./xxx" when sharing "." */
  638.  
  639.     while((dp = readdir(dirp)))
  640.         if (strcmp(dp->d_name,".") && strcmp(dp->d_name,".."))
  641.         {
  642.             int newlen;
  643.  
  644.             if((newlen = filelen + 1 + strlen(dp->d_name)) >= MAXNAMLEN)
  645.             {
  646.                 fprintf(stderr,"shar: file name too long: %s/%s\n",
  647.                         file,dp->d_name);
  648.                 return(1);
  649.             }
  650.             sprintf(file + filelen,"/%s",dp->d_name);
  651.  
  652.             if(walkdown(rtn,file,newlen,rname))
  653.                 return(1);
  654.  
  655.             file[filelen] = '\0';    /* in case we print any error messages */
  656.         }
  657.  
  658. #ifdef CLOSEDIR_VOID
  659.     closedir(dirp);
  660. #else /* CLOSEDIR_VOID */
  661.     if(closedir(dirp))
  662.     {
  663.         fprintf(stderr,"shar: unable to close directory %s",file);
  664.         return(1);
  665.     }
  666. #endif /* CLOSEDIR_VOID */
  667.     return(0);
  668. }
  669.  
  670. int
  671. walktree(rtn,rootname)                /* real walktree */
  672. int (*rtn)(/*file,rname*/);    /* may also assume fst is set */
  673. char *rootname;
  674. {
  675.     char file[MAXNAMLEN];
  676.     int filelen;
  677.     register char *rname;
  678.  
  679.     if((filelen = strlen(rootname)) >= MAXNAMLEN)
  680.     {
  681.         fprintf(stderr,"shar: file name too long: %s\n",rootname);
  682.         return(1);
  683.     }
  684.     strcpy(file,rootname);
  685.  
  686.     if(FileStrip)
  687.     { /* use just the filename */
  688.         rname = file + filelen;
  689.         while(rname > file && *rname != '/')
  690.             --rname;
  691.         if(*rname == '/')
  692.             ++rname;
  693.     }
  694.     else
  695.         rname = file;
  696.     if(!strncmp(rname,"./",2) && rname[2])
  697.         rname += 2;
  698.  
  699.     return(walkdown(rtn,file,filelen,rname));
  700. }
  701.  
  702. #endif /* NO_WALKTREE */
  703.  
  704. int
  705. onecheck(file,rname)
  706. char *file, *rname;
  707. {
  708.     if(access(file,04))
  709.     {
  710.         fprintf(stderr,"shar: Can't access %s\n",file);
  711.         return(1);
  712.     }
  713.  
  714.     return(0);
  715. }
  716.  
  717. int
  718. oneheader(file,rname)
  719. char *file, *rname;
  720. {
  721.     fprintf(fpout,"# %6ld %s %s\n",fst.st_size,
  722.         mode_map(fst.st_mode & ~(S_ISUID|S_ISGID|S_ISVTX),(char *)0),rname);
  723.     return(0);
  724. }
  725.  
  726. header(argc,argv)
  727. char **argv;
  728. {
  729. int i;
  730. FILE *fpsource;    /* pipe temp */
  731. char s128[128];
  732. long now;
  733. struct tm *utc;
  734. struct tm *gmtime();
  735.  
  736.     /* see if any conflicting options */
  737.     if(limit && !filenum)
  738.     { /* can't rename what you don't have */
  739.         fprintf(stderr,"Can't use -l or -L option without -o\n");
  740.         helpuser();
  741.         return(1);
  742.     }
  743.  
  744.     for(i = 0; i < argc; i++)
  745.     { /* skip positional parameters */
  746.         if(PosParam &&
  747.             (strcmp(argv[i],"-B") == 0 ||
  748.              strcmp(argv[i],"-T") == 0 ||
  749.              strcmp(argv[i],"-C") == 0))
  750.             continue;
  751.  
  752.         if(walktree(onecheck,argv[i]))
  753.             return(1);
  754.     }
  755.  
  756.     if(Archive_name)
  757.     {
  758.         fprintf(fpout,"Submitted-by: %s\n",submitter);
  759.         fprintf(fpout,"Archive-name: %s%s%02d\n\n",
  760.             sharname,(strchr(sharname,'/')) ? "" : "/part",
  761.             (filenum) ? filenum : 1);
  762.     }
  763.  
  764.     if(Cut)
  765.         fputs(CutMessage,fpout);
  766.     fputs("#!/bin/sh\n",fpout);
  767.     if(sharname)
  768.         fprintf(fpout,"# This is %s, a shell archive (produced by shar %s)\n",
  769.             sharname,revision);
  770.     else
  771.         fprintf(fpout,"# This is a shell archive (produced by shar %s)\n",
  772.             revision);
  773.     fputs("# To extract the files from this archive, save it to a file, remove\n",
  774.         fpout);
  775.     fputs("# everything above the \"!/bin/sh\" line above, and type \"sh file_name\".\n#\n",
  776.         fpout);
  777.  
  778.     time(&now);
  779.     utc = gmtime(&now);
  780.     fprintf(fpout,"# made %02d/%02d/%04d %02d:%02d UTC by %s\n",
  781.         utc->tm_mon + 1,utc->tm_mday,utc->tm_year + 1900,
  782.         utc->tm_hour,utc->tm_min,
  783.         submitter);
  784.  
  785. #if defined(SYS5)
  786.     if(!(fpsource = popen("/bin/pwd","r")))
  787.         return(-1);
  788.     fgets(s128,sizeof(s128),fpsource);
  789.     s128[strlen(s128) - 1] = 0;
  790.     fclose(fpsource);
  791. #else
  792. #if defined(BSD42) || defined(sun)
  793.     getwd(s128);
  794. #else
  795. #include "Need_conditional_compile_fix"
  796. #endif
  797. #endif
  798.     fprintf(fpout,"# Source directory %s\n",s128);
  799.  
  800.     fprintf(fpout,"#\n# existing files %s\n",
  801.         (eXists) ? "will NOT be overwritten unless -c is specified" 
  802.             : ((InterOW) ? "MAY be overwritten"
  803.                 : "WILL be overwritten"));
  804.  
  805.     if(InterOW)
  806.         fputs("# The unsharer will be INTERACTIVELY queried.\n",fpout);
  807.  
  808.     if(Vanilla)
  809.     {
  810.         fputs("# This format requires very little intelligence at unshar time.\n",fpout);
  811.         fputs("# ",fpout);
  812.         if(eXists || Split)
  813.             fputs("\"if test\", ",fpout);
  814.         if(Split)
  815.             fputs("\"cat\", \"rm\", ",fpout);
  816.         fputs("\"echo\", \"true\", and \"sed\" may be needed.\n",fpout);
  817.     }
  818.  
  819.     if(Split)
  820.     { /* may be split, explain */
  821.         fputs("#\n",fpout);
  822.         TypePos = ftell(fpout);
  823.         fprintf(fpout,"%-75s\n%-75s\n","#","#");
  824.     }
  825.  
  826.     fputs("#\n# This shar contains:\n",fpout);
  827.     fputs("# length  mode       name\n",fpout);
  828.     fputs("# ------ ---------- ------------------------------------------\n",
  829.         fpout);
  830.     for(i = 0; i < argc; i++)
  831.     { /* output names of files but not parameters */
  832.         if(PosParam &&
  833.             (strcmp(argv[i],"-B") == 0 ||
  834.              strcmp(argv[i],"-T") == 0 ||
  835.              strcmp(argv[i],"-C") == 0))
  836.             continue;
  837.         if(walktree(oneheader,argv[i]))
  838.             exit(1);
  839.     }
  840.     fputs("#\n",fpout);
  841.  
  842.     setTOUCH();
  843.  
  844.     if(Split)
  845.     { /* now check the sequence */
  846.         fputs("if test -r _shar_seq_.tmp; then\n",fpout);
  847.         fputs("\techo 'Must unpack archives in sequence!'\n",fpout);
  848.         fputs("\techo Please unpack part `cat _shar_seq_.tmp` next\n",fpout);
  849.         fputs("\texit 1\nfi\n",fpout);
  850.     }
  851.     return(0);
  852. }
  853.  
  854. #define MAX_MKDIR_ALREADY    128    /* ridiculously enough */
  855. char *mkdir_already[MAX_MKDIR_ALREADY];
  856. int mkdir_already_count = 0;
  857.  
  858. void
  859. gen_mkdir(path)
  860. char *path;
  861. {
  862. register int ialready;
  863. char *cptr;
  864.  
  865. /* if already generated code for this dir creation, don't do again */
  866.     for(ialready = 0; ialready < mkdir_already_count; ialready++)
  867.     {
  868.         if(!strcmp(path,mkdir_already[ialready]))
  869.             return;
  870.     }
  871.  
  872. /* haven't done this one */
  873.     if(mkdir_already_count == MAX_MKDIR_ALREADY)
  874.     {
  875.         fprintf(stderr,"too many directories for mkdir generation\n");
  876.         exit(255);
  877.     }
  878.     if(!(cptr = mkdir_already[mkdir_already_count++] = malloc(strlen(path)+1)))
  879.     {
  880.         fprintf(stderr,"out of memory for mkdir generation\n");
  881.         exit(255);
  882.     }
  883.     strcpy(cptr,path);
  884.  
  885. /* generate the text */
  886.     fprintf(fpout,"if test ! -d '%s'; then\n",path);
  887.     if(Verbose)
  888.         fprintf(fpout,"    echo 'x - creating directory %s'\n",path);
  889.     fprintf(fpout,"    mkdir '%s'\n",path);
  890.     fputs("fi\n",fpout);
  891.  
  892. }    /* end of gen_mkdir */
  893.  
  894. void
  895. gen_mkdir_script(path)
  896. register char *path;
  897. {
  898. register char *cptr;
  899.  
  900.     for(cptr = strchr(path,'/'); cptr; cptr = strchr(cptr + 1,'/'))
  901.     {
  902.         /* avoid empty string if leading or double '/' */
  903.         if(cptr == path || *(cptr - 1) == '/')
  904.             continue;
  905.         /* omit '.' */
  906.         if((*(cptr - 1) == '.') && ((cptr == path + 1) || (*(cptr - 2) == '/')))
  907.             continue;
  908.         *cptr = 0;                /* temporarily terminate string */
  909.         gen_mkdir(path);
  910.         *cptr = '/';
  911.     }
  912. }    /* end of gen_mkdir_script */
  913.  
  914. int
  915. shar(file,RstrName)
  916. char *file, *RstrName;
  917. {
  918. char line[BUFSIZ];
  919. FILE *fpsource;
  920. long cursize,remaining,ftell();
  921. int split = 0;        /* file split flag */
  922. char *filetype;        /* text or binary */
  923. struct tm *lt;
  924. char *filename_base;
  925.  
  926.     /* check to see that this is still a regular file  and readable */
  927.     if((fst.st_mode & S_IFMT) != S_IFREG)
  928.     { /* this is not a regular file */
  929.         fprintf(stderr,"shar: %s is not a regular file\n",file);
  930.         return(1);
  931.     }
  932.     if(access(file,04))
  933.     {
  934.         fprintf(stderr,"shar: Can't access %s\n",file);
  935.         return(1);
  936.     }
  937.  
  938.     /* if limit set, get the current output length */
  939.     if(limit)
  940.     {
  941.         cursize = ftell(fpout);
  942.         remaining = (limit * 1024L) - cursize;
  943.         DeBug("In shar: remaining size %ld\n",remaining);
  944.         
  945.         if(!Split && cursize > EndHeadPos &&
  946.             (Binary ? fst.st_size + fst.st_size/3 : fst.st_size) > remaining)
  947.         { /* change to another file */
  948.             DeBug("Newfile, remaining %ld, ",remaining);
  949.             DeBug("limit still %d\n",limit);
  950.  
  951.             /* close the "&&" and report an error if any of the above failed */
  952.             fprintf(fpout,"true || echo 'restore of %s failed'\n",RstrName);
  953.  
  954.             fprintf(fpout, "echo End of part %d, continue with part %d\n",
  955.                 filenum,filenum + 1);
  956.             fputs("exit 0\n",fpout);
  957.  
  958.             fclose(fpout);
  959.  
  960.             /* Clear mkdir_already in case the user unshars out of order */
  961.             while (mkdir_already_count > 0)
  962.                 free(mkdir_already[--mkdir_already_count]);
  963.  
  964.             /* form the next filename */
  965.             sprintf(filename,"%s%02d",outname,++filenum);
  966.             fpout = fopen(filename,"w");
  967.             if(Verbose)
  968.                 fprintf(stderr,"Starting file %s\n",filename);
  969.  
  970.             if(Archive_name)
  971.             {
  972.                 fprintf(fpout,"Submitted-by: %s\n",submitter);
  973.                 fprintf(fpout,"Archive-name: %s%s%02d\n\n",
  974.                     sharname,(strchr(sharname,'/')) ? "" : "/part",
  975.                     (filenum) ? filenum : 1);
  976.             }
  977.  
  978.             if(Cut)
  979.                 fputs(CutMessage,fpout);
  980.  
  981.             fputs("#!/bin/sh\n",fpout);
  982.             fprintf(fpout,"# This is part %02d of %s\n",
  983.                 filenum,(sharname) ? sharname : "a multipart archive");
  984.  
  985.             setTOUCH();
  986.  
  987.             EndHeadPos = ftell(fpout);
  988.         }
  989.     }
  990.  
  991.     fprintf(fpout,"# ============= %s ==============\n",RstrName);
  992.  
  993.     gen_mkdir_script(RstrName);
  994.  
  995.     /* if mixed, determine the file type */
  996.     if(Mixed)
  997.     {
  998.         int count;
  999.         sprintf(line,"file %s | egrep -c \"text|shell\"",file);
  1000.         fpsource = popen(line,"r");
  1001.         fscanf(fpsource,"%d",&count);
  1002.         pclose(fpsource);
  1003.         Binary = (count != 1);
  1004.     }
  1005.  
  1006.     if(Binary)
  1007.     { /* fork a uuencode process */
  1008.         static int pid,pipex[2];
  1009.  
  1010.         pipe(pipex);
  1011.         fflush(fpout);
  1012.  
  1013.         if(pid = fork())
  1014.         { /* parent, create a file to read */
  1015.             if(pid < 0)
  1016.             {
  1017.                 fprintf(stderr,"could not fork!\n");
  1018.                 exit(1);
  1019.             }
  1020.             close(pipex[1]);
  1021.             fpsource = fdopen(pipex[0],"r");
  1022.             filetype = (Compress ? "Compressed" : "Binary");
  1023.         }
  1024.         else
  1025.         { /* start writing the pipe with encodes */
  1026.             FILE *outptr;
  1027.  
  1028.             if(Compress)
  1029.             {
  1030.                 sprintf(line, "compress -b%d < '%s'", CompressBits, file);
  1031.                 fpsource = popen(line, "r");
  1032.             }
  1033.             else
  1034.                 fpsource = fopen(file, "rb");
  1035.             outptr = fdopen(pipex[1],"w");
  1036.             fprintf(outptr,"begin 600 %s\n",
  1037.                 (Compress ? "_shar_cmp_.tmp" : RstrName));
  1038.             encode(fpsource,outptr);
  1039.             fprintf(outptr,"end\n");
  1040.             if(Compress)
  1041.                 pclose(fpsource);
  1042.             else
  1043.             {
  1044.                 fclose(fpsource);
  1045.             }
  1046.             exit(0);
  1047.         }
  1048.     }
  1049.     else
  1050.     {
  1051.         fpsource = fopen(file,"r");
  1052.         filetype = "Text";
  1053.     }
  1054.  
  1055.     if(fpsource)
  1056.     {
  1057.         /* protect existing files */
  1058.         if(eXists)
  1059.         {
  1060.             fprintf(fpout,"if test -f '%s' -a X\"$1\" != X\"-c\"; then\n",
  1061.                 RstrName);
  1062.             if(InterOW)
  1063.             {
  1064.                 fputs("\tcase $wish in\n",fpout);
  1065.                 fprintf(fpout,"\tA*|a*) echo 'x - overwriting %s';;\n",
  1066.                     RstrName);
  1067.                 fprintf(fpout,
  1068.         "\t*) echo '? - overwrite %s -- [No], [Y]es, [A]ll, [Q]uit? '\n",
  1069.                     RstrName);
  1070.                 fputs("\t\tread wish;;\n",fpout);
  1071.                 fputs("\tesac\n",fpout);
  1072.                 fputs("\tcase $wish in\n",fpout);
  1073.                 fputs("\tQ*|q*) echo aborted; exit 86;;\n",fpout);
  1074.                 fputs("\tA*|a*|Y*|y*) x=Y;;\n",fpout);
  1075.                 fputs("\t*) x=N;;\n",fpout);
  1076.                 fputs("\tesac\n",fpout);
  1077.                 fputs("else\n",fpout);
  1078.                 fputs("\tx=Y\n",fpout);
  1079.                 fputs("fi\n",fpout);
  1080.                 fputs("if test $x != Y; then\n",fpout);
  1081.                 fprintf(fpout,"\techo 'x - skipping %s'\n",RstrName);
  1082.             }
  1083.             else
  1084.                 fprintf(fpout,"\techo 'x - skipping %s (File already exists)'\n",
  1085.                     RstrName);
  1086.             if (Split)
  1087.                 fputs("\trm -f _shar_wnt_.tmp\n",fpout);
  1088.             fputs("else\n",fpout);
  1089.             if (Split)
  1090.                 fputs("> _shar_wnt_.tmp\n",fpout);    
  1091.         }
  1092.  
  1093.         fprintf(stderr,"shar: saving %s (%s)\n",file,filetype);
  1094.         if(Verbose)
  1095.         { /* info on archive and unpack */
  1096.             fprintf(fpout,"echo 'x - extracting %s (%s)'\n",
  1097.                 RstrName,filetype);
  1098.         }
  1099.         if(Binary)
  1100.         { /* run sed through uudecode (via temp file if might get split) */
  1101.             fprintf(fpout, "sed 's/^%c//' << '%s' %s &&\n",
  1102.                    PREFIX,Delim,
  1103.                 (AvoidPipes ? "> _shar_tmp_.tmp" : "| uudecode"));
  1104.         }
  1105.         else
  1106.         { /* just run it into the file */
  1107.             fprintf(fpout,"sed 's/^%c//' << '%s' > '%s' &&\n",
  1108.                 PREFIX,Delim,RstrName);
  1109.         }
  1110.         while(fgets(line,BUFSIZ,fpsource))
  1111.         { /* output a line and test the length */
  1112.             if(OptPREFIX && isgraph(line[0]) && line[0] != PREFIX
  1113. #ifdef STRCMP_IS_FAST
  1114.                && strcmp(line,Delim)
  1115. #else /* STRCMP_IS_FAST */
  1116.                && (line[0] != Delim[0] || strcmp(line,Delim))
  1117. #endif /* STRCMP_IS_FAST */
  1118. #ifdef STRNCMP_IS_FAST
  1119.                && strncmp(line,"exit 0",6)    /* See unshar -e: avoid "exit 0" */
  1120.                && strncmp(line,"From",4)    /* Don't let mail prepend a ">" */
  1121. #else /* STRNCMP_IS_FAST */
  1122.                && (line[0] != 'e'            /* See unshar -e: avoid "exit 0" */
  1123.                    || strncmp(line,"exit 0",6))
  1124.                && (line[0] != 'F'            /* Don't let mail prepend a ">" */
  1125.                       || strncmp(line,"From",4))
  1126. #endif /* STRNCMP_IS_FAST */
  1127.               )
  1128.                 fputs(line,fpout);
  1129.             else
  1130.             {
  1131.                 fprintf(fpout,"%c%s",PREFIX,line);
  1132.                 --remaining;    /* count PREFIX (in case Split is in effect) */
  1133.             }
  1134. #ifdef MSDOS    /* This probably doesn't work but accounts for some old code */
  1135.             if(Split && (remaining -= strlen(line) + 1) < 0)    /* 1 extra for CR */
  1136. #else /* MSDOS */
  1137.             if(Split && (remaining -= strlen(line)) < 0)
  1138. #endif /* MSDOS */
  1139.             { /* change to another file */
  1140.                 DeBug("Newfile, remaining %ld, ",remaining);
  1141.                 DeBug("limit still %d\n",limit);
  1142.  
  1143.                 if(line[strlen(line) - 1] != '\n')
  1144.                     fputc('\n',fpout);
  1145.  
  1146.                 fprintf(fpout,"%s\n",Delim);
  1147.  
  1148.                 /* close the "&&" and report an error if any of the above failed */
  1149.                 fprintf(fpout,"true || echo 'restore of %s failed'\n",RstrName);
  1150.  
  1151.                 if (eXists)
  1152.                     fputs("fi\n",fpout);
  1153.  
  1154.                 if(Verbose)
  1155.                 { /* output some reassurance */
  1156.                     fprintf(fpout, "echo 'End of %s part %d'\n",
  1157.                         (sharname) ? sharname : "",filenum);
  1158.                     fprintf(fpout, "echo 'File %s is continued in part %d'\n",
  1159.                         RstrName,filenum + 1);
  1160.                 }
  1161.                 else
  1162.                     fprintf(fpout,
  1163.                         "echo 'End of part %d, continue with part %d'\n",
  1164.                         filenum,filenum + 1);
  1165.                 fprintf(fpout,"echo %d > _shar_seq_.tmp\n",filenum + 1);
  1166.                 fputs("exit 0\n",fpout);
  1167.  
  1168.                 if(filenum == 1)
  1169.                 { /* rewrite the info lines on the firstheader */
  1170.                     fseek(fpout,TypePos,0);
  1171.                     fprintf(fpout,"%-75s\n%-75s\n",
  1172.                         "# This is part 1 of a multipart archive",
  1173.                         "# do not concatenate these parts, unpack them in order with /bin/sh");
  1174.                 }
  1175.                 fclose(fpout);
  1176.  
  1177.                 /* form the next filename */
  1178.                 sprintf(filename,"%s%02d",outname,++filenum);
  1179.                 fpout = fopen(filename,"w");
  1180.  
  1181.                 if(Archive_name)
  1182.                 {
  1183.                     fprintf(fpout,"Submitted-by: %s\n",submitter);
  1184.                     fprintf(fpout,"Archive-name: %s%s%02d\n\n",
  1185.                         sharname,(strchr(sharname,'/')) ? "" : "/part",
  1186.                         (filenum) ? filenum : 1);
  1187.                 }
  1188.  
  1189.                 if(Cut)
  1190.                     fputs(CutMessage,fpout);
  1191.                 fputs("#!/bin/sh\n",fpout);
  1192.  
  1193.                 fprintf(fpout,"# this is %s (part %d of %s)\n",
  1194.                     ((filename_base = strrchr(filename,'/'))
  1195.                         ? filename_base + 1
  1196.                         : filename),
  1197.                     filenum,
  1198.                     (sharname) ? sharname : "a multipart archive");
  1199.                 fputs(
  1200.         "# do not concatenate these parts, unpack them in order with /bin/sh\n",
  1201.                     fpout);
  1202.                 fprintf(fpout,"# file %s continued\n#\n",RstrName);
  1203.  
  1204.                 setTOUCH();
  1205.                 
  1206.                 fputs("if test ! -r _shar_seq_.tmp; then\n",fpout);
  1207.                 fputs("\techo 'Please unpack part 1 first!'\n",fpout);
  1208.                 fputs("\texit 1\nfi\n",fpout);
  1209.                 fputs("(read Scheck\n",fpout);
  1210.                 fprintf(fpout," if test \"$Scheck\" != %d; then\n",filenum);
  1211.                 fputs("\techo Please unpack part \"$Scheck\" next!\n",
  1212.                     fpout);
  1213.                 fputs("\texit 1\n",fpout);
  1214.                 fputs(" else\n\texit 0\n fi\n",fpout);
  1215.                 fputs(") < _shar_seq_.tmp || exit 1\n",fpout);
  1216.  
  1217.                 if(eXists)
  1218.                     if(Verbose)
  1219.                     { /* keep everybody informed */
  1220.                         fputs("if test ! -f _shar_wnt_.tmp; then\n",fpout);
  1221.                         fprintf(fpout,"\techo 'x - still skipping %s'\n",
  1222.                                 RstrName);
  1223.                         fputs("else\n",fpout);
  1224.                     }
  1225.                     else
  1226.                         fputs("if test -f _shar_wnt_.tmp; then\n",fpout);
  1227.  
  1228.                 if(Verbose)
  1229.                 { /* keep everybody informed */
  1230.                     fprintf(stderr,"Starting file %s\n",filename);
  1231.                     fprintf(fpout,"echo 'x - continuing file %s'\n",RstrName);
  1232.                 }
  1233.                 fprintf(fpout,"sed 's/^%c//' << '%s' >> '%s' &&\n",
  1234.                     PREFIX,Delim,
  1235.                     (Binary ? "_shar_tmp_.tmp" : RstrName));
  1236.                 remaining = limit * 1024L;
  1237.                 split = 1;
  1238.             }
  1239.         }
  1240.  
  1241.         (void) fclose(fpsource);
  1242.         while(wait((int *)0) >= 0)
  1243.             ;
  1244.  
  1245.         if(line[strlen(line) - 1] != '\n')
  1246.             fputc('\n',fpout);
  1247.  
  1248.         fprintf(fpout,"%s\n",Delim);
  1249.         if(split && Verbose)
  1250.             fprintf(fpout,"echo 'File %s is complete' &&\n",RstrName);
  1251.  
  1252.         /* if this file was uuencoded w/Split, decode it and drop the temp */
  1253.         if(Binary && AvoidPipes)
  1254.         {
  1255.             if(Verbose)
  1256.                 fprintf(fpout,"echo 'uudecoding file %s' &&\n",RstrName);
  1257.             fputs("uudecode < _shar_tmp_.tmp && rm -f _shar_tmp_.tmp &&\n",fpout);
  1258.         }
  1259.  
  1260.         /* if this file was compressed, uncompress it and drop the temp */
  1261.         if(Compress)
  1262.         {
  1263.             if(Verbose)
  1264.                 fprintf(fpout,"echo 'uncompressing file %s' &&\n",RstrName);
  1265.             fprintf(fpout,
  1266.                 "compress -d < _shar_cmp_.tmp > '%s' && rm -f _shar_cmp_.tmp &&\n",
  1267.                 RstrName);
  1268.         }
  1269.  
  1270.         if(Touch)
  1271.         {
  1272.             /* set the dates as they were */
  1273.             lt = localtime(&fst.st_mtime);
  1274.             fprintf(fpout,"$TOUCH -am %02d%02d%02d%02d%02d '%s' &&\n",
  1275.                 lt->tm_mon + 1,
  1276.                 lt->tm_mday,
  1277.                 lt->tm_hour,
  1278.                 lt->tm_min,
  1279.                 lt->tm_year,
  1280.                 RstrName);
  1281.         }
  1282.  
  1283.         if(Vanilla)
  1284.         {
  1285.             /* close the "&&" and report an error if any of the above failed */
  1286.             fprintf(fpout,"true || echo 'restore of %s failed'\n",RstrName);
  1287.         }
  1288.         else
  1289.         {
  1290.             /* set the permissions as they were */
  1291.             fprintf(fpout,"chmod %04o %s ||\n",
  1292.                 fst.st_mode & 00777,RstrName);
  1293.  
  1294.             /* report an error if any of the above failed */
  1295.             fprintf(fpout,"echo 'restore of %s failed'\n",RstrName);
  1296.  
  1297.             if(Wc_c)
  1298.             { /* validate the transferred file */
  1299.                 FILE *pfp;
  1300.                 char command[BUFSIZ];
  1301.  
  1302.                 sprintf(command,"%s '%s'",WC,file);
  1303.                 if((pfp = popen(command,"r")))
  1304.                 {
  1305.                     char wc[BUFSIZ];
  1306.  
  1307.                     fscanf(pfp,"%s",wc);
  1308.                     fprintf(fpout,"Wc_c=\"`%s '%s'`\"\n",WC,RstrName);
  1309.                     fprintf(fpout,"test %s -eq \"$Wc_c\" ||\n",wc);
  1310.                     fprintf(fpout,
  1311.                         "\techo '%s: original size %s, current size' \"$Wc_c\"\n",
  1312.                         RstrName, wc);
  1313.                     pclose(pfp);
  1314.                 }
  1315.             }
  1316.         }
  1317.  
  1318.         /* if the exists option is in place close the if */
  1319.         if(eXists)
  1320.         {
  1321.             if (Split)
  1322.                 fputs("rm -f _shar_wnt_.tmp\n",fpout);
  1323.  
  1324.             fputs("fi\n",fpout);
  1325.         }
  1326.  
  1327.         return(0);
  1328.     }
  1329.     else
  1330.     {
  1331.         fprintf(stderr,"shar: Can't open %s (%s): ",file,filetype);
  1332.         perror("");
  1333.         return(1);
  1334.     }
  1335. }
  1336.  
  1337.  
  1338. char *helpinfo[] =
  1339. {
  1340.     "-V  produce \"vanilla\" shars demanding little of the unshar environment",
  1341.     "-v  verbose messages OFF while executing",
  1342.     "-m  restore file modification dates & times with \"touch\" commands",
  1343.     "-w  don't check with 'wc -c' after unpack",
  1344.     "-a  generate Submitted-by: & Archive-name: headers",
  1345.     "-nXXX   use XXX as the name of the archive (documentation)",
  1346.     "-s  override automatically determined submitter name",
  1347.     "-x  overwrite existing files without checking if they already exist",
  1348.     "-X  interactively overwrite existing files (NOT FOR NET SHARS)",
  1349.     "-B  treat all files as binary, use uuencode",
  1350.     "-T  treat all files as text (default)",
  1351.     "-C  compress and uuencode all files",
  1352.     "-bXX    pass -bXX (default 12) to compress when compressing (implies -C)",
  1353.     "-p  allow positional parameter options. The options \"-B\" and \"-T\"",
  1354.     "    and \"-C\" may be embedded, and files to the right of the",
  1355.     "    option will be processed in the specified mode",
  1356.     "-M  mixed mode. Determine if the files are text or",
  1357.     "    binary and archive correctly.",
  1358.     "-P  use temp files instead of pipes in the shar file",
  1359.     "-F  force the prefix character on every line (even if not required)",
  1360.     "-c  start the shar with a cut line",
  1361.     "-f  restore by filename only, rather than path",
  1362.     "-dXXX   use XXX to delimit the files in the shar",
  1363.     "-oXXX   (or -o XXX) output to file XXX.01 thru XXX.nn",
  1364.     "-lXX    limit output file size to XXk bytes (but don't split files)",
  1365.     "-LXX    limit output file size to XXk bytes (may split files)",
  1366.     "-S      read files to wrap from stdin, ignoring argument line",
  1367.     "\nThe -S option reads filenames one per line from stdin; input",
  1368.     "format must be similar to 'find' output, except that if -p",
  1369.     "is specified, -B, -T or -C may be used (on lines by themselves)",
  1370.     "e.g., find . -type f -print | sort | shar -C -l50 -o /tmp/big",
  1371.     "\nThe 'o' option is required if the 'l' or 'L' option is used",
  1372.     "The 'n' option is required if the 'a' option is used",
  1373.     "\n-a generates sharname/part## headers. If the -a argument contains",
  1374.     "a '/', then /part is not appended",
  1375.     "The automatic submitter name is trivial: essentially `whoami`@`uname`",
  1376.     (char *)0
  1377. };
  1378.  
  1379. helpuser()
  1380. {                /* output a command format message */
  1381.     register char **ptr;
  1382.     fprintf(stderr,
  1383.         "shar %s\nusage: shar [ options ] file ...\n       shar -S [ options ]\n",
  1384.         revision);
  1385.     for(ptr = helpinfo; *ptr; ptr++)
  1386.         fprintf(stderr,"%s\n",*ptr);
  1387.  
  1388.     exit(1);
  1389. }
  1390. /* vi: set tabstop=4 shiftwidth=4: */
  1391.